/* -*-C-*-
 *******************************************************************************
 *
 * File:         sfs.c
 * RCS:          $Id: sfs.c,v 1.2 2009/11/10 21:17:25 npb853 Exp $
 * Description:  Simple File System
 * Author:       Fabian E. Bustamante
 *               Northwestern Systems Research Group
 *               Department of Computer Science
 *               Northwestern University
 * Created:      Tue Nov 05, 2002 at 07:40:42
 * Modified:     Fri Nov 19, 2004 at 15:45:57 fabianb@cs.northwestern.edu
 * Language:     C
 * Package:      N/A
 * Status:       Experimental (Do Not Distribute)
 *
 * (C) Copyright 2003, Northwestern University, all rights reserved.
 *
 *******************************************************************************
 */

#include "sfs.h"
#include "sdisk.h"
#include "brad.h"

//---------------------------Globals--------------------------------
FileSystemHeader header;
directory_index_t currentDir;

#define MAX_OPEN_FILES 9000
OpenFileHandle openFiles[MAX_OPEN_FILES];
bool handleInUse[MAX_OPEN_FILES];

//--------------------------Functions-------------------------------
int sfs_mkfs() {
	fs_init( &header );

	size_t i;
	for ( i = 0; i < MAX_OPEN_FILES; i++ )
		handleInUse[i] = false;

    currentDir = 0;

    return 0;
} /* !sfs_mkfs */

int sfs_mkdir(char *name) {
        return fs_tryMkdir( &header, name, currentDir );
} /* !sfs_mkdir */

int sfs_fcd(char* name) {
		return fs_getDir( &header, name, currentDir, &currentDir );
} /* !sfs_fcd */

int sfs_ls(FILE* f) {
    fs_ls( &header, currentDir, f );
    return 0;
} /* !sfs_ls */

int sfs_fopen(char* name) {
	size_t i;

    char newName[MAX_NAME_LENGTH + 1];
    directory_index_t searchDirectory;
    if ( fs_getDirAndName( &header, name, currentDir, &searchDirectory, newName ) != 0 )
        return -1;

    //Check that file is not already open
    for ( i = 0; i < MAX_OPEN_FILES; i++ )
	{
		if ( handleInUse[i] && strcmp( openFiles[i].file->fileName, newName ) == 0 && openFiles[i].file->parentDirectory == searchDirectory )
			return -1;
	}

    //Make sure not at max open files
	for ( i = 0; i < MAX_OPEN_FILES; i++ )
	{
		if ( !handleInUse[i] )
			break;
	}

	if ( i == MAX_OPEN_FILES )
		return -1;

    //Try to open file
	if ( fs_tryOpenFile( &header, newName, searchDirectory, openFiles + i ) != 0 )
		return -1;

	handleInUse[i] = true;
	return i;
} /* !sfs_fopen */

int sfs_fclose(int fileID) {
	if ( fileID < 0 || fileID >= MAX_OPEN_FILES )
		return -1;

    if ( !handleInUse[fileID] )
    	return -1;

    if ( file_writeToDisk( openFiles[fileID].file, openFiles[fileID].file_data ) != 0 )
        return -1;

	handleInUse[fileID] = false;
	return 0;
} /* !sfs_fclose */

int sfs_fread(int fileID, char *buffer, int length) {
	if ( fileID < 0 || fileID >= MAX_OPEN_FILES )
		return -1;

    if ( !handleInUse[fileID] )
    	return -1;

    OpenFileHandle * handle = openFiles + fileID;

    if ( handle->stream_pointer + length > handle->file->size )
        return -1;

    memcpy( buffer, (char *)handle->file_data + handle->stream_pointer, length );
    handle->stream_pointer += length;

    return length;
}

int sfs_fwrite(int fileID, char *buffer, int length) {
	if ( fileID < 0 || fileID >= MAX_OPEN_FILES )
		return -1;

    if ( !handleInUse[fileID] )
    	return -1;

    OpenFileHandle * handle = openFiles + fileID;

    if ( handle->stream_pointer + length > handle->file->size &&
        fs_expand( &header, handle->file, &handle->file_data, handle->stream_pointer + length - handle->file->size ) != 0 ) {
            return -1;
    }

    memcpy( ((char *)(handle->file_data)) + handle->stream_pointer, buffer, length );
    handle->stream_pointer += length;

    return length;
} /* !sfs_fwrite */

int sfs_lseek(int fileID, int position) {
	if ( fileID < 0 || fileID >= MAX_OPEN_FILES )
		return -1;

    if ( !handleInUse[fileID] )
    	return -1;

    if ( position < 0 || position >= openFiles[fileID].file->size )
        return -1;

    openFiles[fileID].stream_pointer = position;

    return position;
} /* !sfs_lseek */

int sfs_rm(char *file_name) {
    return fs_rm( &header, currentDir, file_name );
} /* !sfs_rm */
